package top.gytf.unifiedcall.producer.support.exception;

import cn.hutool.core.collection.CollUtil;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import top.gytf.unifiedcall.common.support.UnifiedCallApiContract;
import top.gytf.unifiedcall.model.code.builtin.BuiltinStatusCode;
import top.gytf.unifiedcall.model.exception.BaseException;
import top.gytf.unifiedcall.common.api.ApiDefinition;
import top.gytf.unifiedcall.producer.response.ResponseHandler;
import top.gytf.unifiedcall.producer.response.ResponseHandlerContext;
import top.gytf.unifiedcall.producer.support.wrap.WrapUnifiedResponseHandler;
import top.gytf.unifiedcall.producer.support.wrap.WrapUnifiedResponseParameter;

import java.util.List;

import static top.gytf.unifiedcall.producer.constant.ResponseHandlerParameterConstants.WRAP_UNIFIED_RESPONSE_PARAMETER;

/**
 * 异常处理
 */
@Slf4j
@Setter
public class ExceptionResponseHandler implements ResponseHandler {
    public static final int POSITION = WrapUnifiedResponseHandler.POSITION - 100;

    private final CompositeExceptionAdapter exceptionAdapter;
    private final boolean hasMessageWhenUnknownException;
    private final boolean printHandledException;

    public ExceptionResponseHandler(List<ExceptionAdapter> exceptionAdapters, boolean hasMessageWhenUnknownException, boolean printHandledException) {
        this.exceptionAdapter = new CompositeExceptionAdapter(exceptionAdapters);
        this.hasMessageWhenUnknownException = hasMessageWhenUnknownException;
        this.printHandledException = printHandledException;
    }

    @Override
    public int order() {
        return POSITION;
    }

    @Override
    public boolean isSupported(ApiDefinition apiDefinition) {
        return CollUtil.isNotEmpty(apiDefinition.getApiContracts(UnifiedCallApiContract.class));
    }

    @Override
    public void handle(ResponseHandlerContext context) {
        if (!(context.getResponse() instanceof Throwable throwable)) {
            return;
        }

        if (printHandledException) {
            log.error("统一调用处理了异常", throwable);
        }

        WrapUnifiedResponseParameter parameter = context.computeParameterIfAbsent(WRAP_UNIFIED_RESPONSE_PARAMETER,
                WrapUnifiedResponseParameter.class, WrapUnifiedResponseParameter::new);
        Object data = null;

        // 通过适配器转换未知异常
        if (!(throwable instanceof BaseException) && exceptionAdapter.isSupported(throwable.getClass())) {
            throwable = exceptionAdapter.convert(throwable);
        }

        if (throwable instanceof BaseException baseException) {
            // 如果是BaseException，则直接使用其数据
            parameter.setCode(baseException.getCode());
            data = baseException.getMessage();
        } else {
            // 否则未知错误
            parameter.setCode(BuiltinStatusCode.UNKNOWN_FAIL);
            parameter.setMessage(BuiltinStatusCode.UNKNOWN_FAIL.message());
            if (hasMessageWhenUnknownException) {
                data = throwable.getMessage();
            }
        }

        // 清空异常响应
        context.setResponse(data);
    }
}